package com.huatai.datacenter.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.huatai.common.error.exception.ServiceException;
import com.huatai.datacenter.mapper.CallBack;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

/**
 * 缓存工具类
 * @author Lion
 * @date 2023/7/10  14:46
 */
public class RedisUtil {

	/**
	 * 获取表对应的缓存key，
	 * 其中key的密码规则为：appid:DB-TABLE:表名:sql语句from后面的值(多个是，将以:符号分隔)，可以为空:
	 *
	 * @param table
	 * @param fromSuffix from值后面的后缀，可以为空
	 * @return 在key前缀中会带上appId
	 */
	public static String buildDbTableKey(Class<?> table, Object... fromSuffix) {
		//BaseProperties properties = ApplicationContextUtil.getBean(BaseProperties.class);
		if (ObjectUtil.isEmpty(fromSuffix)) {
			return StrUtil.format( ":DB-TABLE:{}:ALL", table.getName());
		} else {
			return StrUtil.format(":DB-TABLE:{}:{}", table.getName(), fromSuffix.length > 0 ? StrUtil.join(":", fromSuffix) : fromSuffix);
		}
	}

	/**
	 * 设置缓存值
	 *
	 * @param key
	 * @param value
	 * @param timeout 缓存过期时间，如Duration.ofHours(12)
	 * @return 当缓存不存在时（null或为空），返回回调方法中的值
	 */
	public static void setString(String key, String value, Duration timeout) {
		AssertI.notBlank(key);
		StringRedisTemplate redisTemplate = ApplicationContextUtil.getBean(StringRedisTemplate.class);
		if (redisTemplate == null) {
			throw new ServiceException("缓存对象为空,无法获取[{}]");
		}
		redisTemplate.opsForValue().set(key, value, timeout);
	}

	/**
	 * 获取缓存值
	 *
	 * @param key
	 */
	public static String getString(String key, String defaultValue) {
		AssertI.notBlank(key);
		StringRedisTemplate redisTemplate = ApplicationContextUtil.getBean(StringRedisTemplate.class);
		if (redisTemplate == null) {
			throw new ServiceException("缓存对象为空,无法获取[{}]");
		}
		String value = redisTemplate.opsForValue().get(key);
		return StrUtil.isBlank(value) ? defaultValue : value;
	}

	/**
	 * 获取缓存值，若不存在，则调用回调方法获取值，同时将回调方法中的返回值保存至缓存中
	 *
	 * @param key
	 * @param callBack
	 * @param inputs
	 * @return 当缓存不存在时（null或为空），返回回调方法中的值
	 */
	public static String getStringOSet(String key, CallBack callBack, Object... inputs) {
		AssertI.notBlank(key);
		StringRedisTemplate redisTemplate = ApplicationContextUtil.getBean(StringRedisTemplate.class);
		if (redisTemplate == null) {
			throw new ServiceException("缓存对象为空,无法获取[{}]");
		}
		String value = redisTemplate.opsForValue().get(key);
		if (StrUtil.isBlank(value)) {
			Object temp = callBack.execute(inputs);
			value = temp == null ? null : temp.toString();
			if (StrUtil.isNotBlank(value)) {
				redisTemplate.opsForValue().set(key, value, Duration.ofHours(12));
			}
		}
		return value;
	}

	/**
	 * 获取值，如果不存在的话， 调回调方法获取值，并重新插入
	 *
	 * @param keys
	 * @return
	 */
	public static Boolean deleteString(String... keys) {
		AssertI.notEmpty(keys);
		StringRedisTemplate redisTemplate = ApplicationContextUtil.getBean(StringRedisTemplate.class);
		if (redisTemplate == null) {
			throw new ServiceException("缓存对象为空,无法删除[{}]");
		}
		List<String> redisKeys = new ArrayList<>();
		for (String key : keys) {
			//通配符匹配: *：通配任意多个字符, ?：通配单个字符, []：通配括号内的某一个字符
			redisKeys.addAll(redisTemplate.keys(key));
		}
		//当redis中存在key时，删除缓存
		if (ObjectUtil.isNotEmpty(redisKeys)) {
			return redisTemplate.delete(redisKeys) > 0;
		}
		return true;
	}

	/**
	 * 获取值，如果不存在的话， 调回调方法获取值，并重新插入
	 *默认缓存时间是12H
	 * @param key
	 * @param callBack 但无对应值时，执行的回调方法
	 * @param inputs
	 * @return
	 */
	public static <T> T getOrSet(String key, CallBack<T> callBack, Object... inputs) {
		T value = get(key);
		if (ObjectUtil.isEmpty(value)) {
			value = callBack.execute(inputs);
			if (value != null) {
				set(key, value);
			}
		}
		return value == null ? null : (T) value;
	}

	/**
	 * 设置缓存值,默认缓存时间是12H
	 *
	 * @param key
	 * @param value
	 */
	public static void set(String key, Object value) {
		set(key, value, Duration.ofHours(12));
	}

	/**
	 * 设置缓存值
	 *
	 * @param key
	 * @param value
	 * @param timeout 缓存过期时间，如Duration.ofHours(12)
	 * @return 当缓存不存在时（null或为空），返回回调方法中的值
	 */
	public static void set(String key, Object value, Duration timeout) {
		AssertI.notBlank(key);
		RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) ApplicationContextUtil.getBean("amyRedisTemplate");
		if (redisTemplate == null) {
			throw new ServiceException("缓存对象[redisTemplate]为空,无法获取[{}]");
		}
		redisTemplate.opsForValue().set(key, value, timeout);
	}

	/**
	 * 获取缓存值
	 *
	 * @param key
	 */
	public static <T> T get(String key) {
		AssertI.notBlank(key);
		RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) ApplicationContextUtil.getBean("amyRedisTemplate");

		if (redisTemplate == null) {
			throw new ServiceException("缓存对象[redisTemplate]为空,无法获取[{}]");
		}
		Object value = redisTemplate.opsForValue().get(key);
		return value == null ? null : (T) value;
	}

	/**
	 * 获取缓存值
	 *
	 * @param key
	 */
	public static <T> T get(String key, T defaultValue) {
		T value = get(key);
		return value == null ? defaultValue : (T) value;
	}

	/**
	 * 获取值，如果不存在的话， 调回调方法获取值，并重新插入
	 *
	 * @param keys *：通配任意多个字符, ?：通配单个字符, []：通配括号内的某一个字符
	 * @return
	 */
	public static Boolean delete(String... keys) {
		AssertI.notEmpty(keys);
		RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) ApplicationContextUtil.getBean("amyRedisTemplate");
		if (redisTemplate == null) {
			throw new ServiceException("缓存对象[redisTemplate]为空,无法删除[{}]");
		}
		List<String> redisKeys = new ArrayList<>();
		for (String key : keys) {
			//通配符匹配: *：通配任意多个字符, ?：通配单个字符, []：通配括号内的某一个字符
			redisKeys.addAll(redisTemplate.keys(key));
		}
		//当redis中存在key时，删除缓存
		if (ObjectUtil.isNotEmpty(redisKeys)) {
			return redisTemplate.delete(redisKeys) > 0;
		}
		return true;
	}
}
